﻿using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using SinsMapPacker;

namespace SinsMapPacker.Editor
{

public partial class MainForm : Form
{
    string mapPackFileName;
    bool isMapPackNew;
    bool isMapPackModified;
    MapPack mapPack;



    public MainForm()
    {
        InitializeComponent();

        foreach (var ext in MapPack.GetAvailableExtensions())
        {
            var icon = Util.GetIconForExt(ext);
            if (icon == null)
            {
                System.Windows.MessageBox.Show(
                    string.Format("Unable to find icon for file type '{0}'", ext),
                    "Error",
                    System.Windows.MessageBoxButton.OK,
                    System.Windows.MessageBoxImage.Error);
                continue;
            }

            mapPackIcons.Images.Add(ext, icon);
        }
    }

    // ************************************
    // Event Handlers
    // ************************************
    #region Event Handlers
    private void NewMapPack_Click(object sender, EventArgs e)
    {
        if (!CloseMapPack())
            return;

        mapPack         = new MapPack();
        mapPackFileName = null;
        isMapPackNew    = true;

        mapPack.ModifiedHandler += new MapPack.ModifiedEvent(MapPackModified);

        SetMapPackControlsOnOff(true);
        PopulateMapPackDirectories();
    }

    private void OpenMapPack_Click(object sender, EventArgs e)
    {
        OpenMapPack();
    }

    private void CloseMapPack_Click(object sender, EventArgs e)
    {
        CloseMapPack();
    }

    private void SaveMapPack_Click(object sender, EventArgs e)
    {
        SaveMapPack();
    }

    private void SaveAsMapPack_Click(object sender, EventArgs e)
    {
        SaveAsMapPack();
    }

    private void FileExit_Click(object sender, EventArgs e)
    {
        Close();
    }

    private void MapPackDirectories_BeforeSelect(object sender, TreeViewCancelEventArgs e)
    {
        var clickedNode = e.Node;

        if ((string)clickedNode.Tag == "root")
        {
            mapPackDirectories.SelectedNode = clickedNode.Nodes[0];
            e.Cancel = true;
        }
    }

    private void MapPackDirectories_AfterSelect(object sender, TreeViewEventArgs e)
    {
        PopulateMapPackFiles();
    }

    private void MapPackFiles_SelectedIndexChanged(object sender, EventArgs e)
    {
        menuMapPackRemoveFile.Enabled = (mapPackFiles.SelectedItems.Count > 0);
    }

    private void MapPackAddFile_Click(object sender, EventArgs e)
    {
        var openFileDlg = new OpenFileDialog();
        openFileDlg.Filter = "*.galaxy; *.tga|*.galaxy; *.tga|All files (*.*)|*.*";
        if (openFileDlg.ShowDialog() != DialogResult.OK)
            return;
        
        try
        {
            mapPack.AddFile(openFileDlg.FileName);
        }
        catch (Exception exp)
        {
            System.Windows.MessageBox.Show(exp.Message);
        }
    }

    private void MapPackRemoveFile_Click(object sender, EventArgs e)
    {
        foreach (ListViewItem item in mapPackFiles.SelectedItems)
            mapPack.RemoveFile(item.Text);
    }

    private void MapPackUnpack_Click(object sender, EventArgs e)
    {
        var folderBrowseDlg = new FolderBrowserDialog();
        if (folderBrowseDlg.ShowDialog() != DialogResult.OK)
            return;

        mapPack.Unpack(folderBrowseDlg.SelectedPath);
    }

    private void MapPack_DragEnter(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(DataFormats.FileDrop))
        {
            var files = (string[])e.Data.GetData(DataFormats.FileDrop);
            foreach (var file in files)
            {
                var ext = Path.GetExtension(file);
                if (!MapPack.GetAvailableExtensions().Contains(ext))
                    return;
            }

            e.Effect = DragDropEffects.Copy;
        }
    }

    private void MapPack_DragDrop(object sender, DragEventArgs e)
    {
        if (!e.Data.GetDataPresent(DataFormats.FileDrop))
            return;

        var files = (string[])e.Data.GetData(DataFormats.FileDrop);
        foreach (var file in files)
        {
            var ext = Path.GetExtension(file);
            if (!MapPack.GetAvailableExtensions().Contains(ext))
                return;
        }

        foreach (var file in files)
            mapPack.AddFile(file);
    }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (!VerifyNoUnsavedChanges())
            e.Cancel = true;
    }

    private void About_Click(object sender, EventArgs e)
    {
        var aboutForm = new AboutForm();
        aboutForm.ShowDialog();
    }

    public void MapPackModified()
    {
        isMapPackModified = true;
        PopulateMapPackFiles();
    }
    #endregion

    // ************************************
    // Utility methods
    // ************************************

    public void OpenMapPack()
    {
        OpenMapPack(null);
    }

    public bool OpenMapPack(string file)
    {
        if (!VerifyNoUnsavedChanges())
            return false;
        
        if (file == null)
        {
            var openFileDlg = new OpenFileDialog();
            openFileDlg.Filter = "Sins Map Pack Files (*.snmp)|*.snmp|All files (*.*)|*.*";
            if (openFileDlg.ShowDialog() != DialogResult.OK)
                return false;
            file = openFileDlg.FileName;
        }

        if (!CloseMapPack())
            return false;

        try
        {
            mapPack         = MapPack.Open(file);
            mapPackFileName = file;
        }
        catch (ApplicationException exp)
        {
            System.Windows.MessageBox.Show(exp.Message);
            return false;
        }
        catch (Exception exp)
        {
            System.Windows.MessageBox.Show(exp.ToString());
            return false;
        }

        mapPack.ModifiedHandler += new MapPack.ModifiedEvent(MapPackModified);

        SetMapPackControlsOnOff(true);
        PopulateMapPackDirectories();

        return true;
    }

    // <summary>
    // Closes the currently open map pack, checking for unsaved changes.
    // </summary>
    private bool CloseMapPack()
    {
        if ( !VerifyNoUnsavedChanges() )
            return false;

        mapPack = null;

        SetMapPackControlsOnOff(false);

        return true;
    }

    private bool VerifyNoUnsavedChanges()
    {
        if (isMapPackModified)
        {
            var mapPackName = mapPackDirectories.Nodes[0].Text;
            var userResponse = System.Windows.MessageBox.Show(
                string.Format("Do you want to save the changes you made to '{0}'?", mapPackName),
                "Sins Map Pack Editor",
                System.Windows.MessageBoxButton.YesNoCancel,
                System.Windows.MessageBoxImage.Exclamation);
            
            if      (userResponse == System.Windows.MessageBoxResult.Yes)
                return SaveMapPack();
            else if (userResponse == System.Windows.MessageBoxResult.Cancel)
                return false;
        }

        isMapPackModified = false;
        isMapPackNew      = false;

        return true;
    }
    
    private void SetMapPackControlsOnOff(bool status)
    {
        menuFileClose.Enabled  = status;
        menuFileSave.Enabled   = status;
        menuFileSaveAs.Enabled = status;

        menuMapPackAddFile.Enabled    = status;
        menuMapPackUnpack.Enabled     = status;

        toolSave.Enabled = status;

        mapPackContainer.Visible = status;
        if (status)
        {
            panelContent.BorderStyle = BorderStyle.None;
        }
        else
        {
            panelContent.BorderStyle = BorderStyle.Fixed3D;
        }
    }

    private void PopulateMapPackDirectories()
    {
        mapPackDirectories.BeginUpdate();
        mapPackDirectories.Nodes.Clear();

        var root = mapPackDirectories.Nodes.Add("");
        root.Text = (mapPackFileName == null) ? "New Map Pack" : Path.GetFileNameWithoutExtension(mapPackFileName);
        root.Tag = "root";
        root.ImageIndex = 1;
        root.SelectedImageIndex = 1;

        foreach (var dir in mapPack.Directories)
        {
            var node = mapPackDirectories.Nodes[0].Nodes.Add(dir);
            node.Tag = dir;
        }

        mapPackDirectories.Nodes[0].Expand();
        mapPackDirectories.SelectedNode = root.Nodes[0];
        mapPackDirectories.EndUpdate();
    }

    private void PopulateMapPackFiles()
    {
        var dir = (string)mapPackDirectories.SelectedNode.Tag;

        // Remove list items that don't exist in the file list.
        foreach (ListViewItem file in mapPackFiles.Items)
        {
            if ( !mapPack.Files(dir).Contains(file.Text) )
                mapPackFiles.Items.Remove(file);
        }

        // Add files that don't exist in the list items.
        foreach (var file in mapPack.Files(dir))
        {
            var existingItem = from ListViewItem listItem in mapPackFiles.Items
                               where listItem.Text == file
                               select listItem;
            
            if ( existingItem.Count() == 0 )
            {
                var newItem = mapPackFiles.Items.Add(file);
                newItem.ImageKey = Path.GetExtension(file);
            }
        }
    }

    private bool SaveMapPack()
    {
        if (isMapPackNew)
        {
            return SaveAsMapPack();
        }
        else
        {
            return WriteMapPack();
        }
    }

    private bool SaveAsMapPack()
    {
        var saveDlg = new SaveFileDialog();
        saveDlg.Filter = "Map Pack Files (*.snmp)|*.snmp|All Files (*.*)|*.*";
        saveDlg.DefaultExt = "snmp";

        if (saveDlg.ShowDialog() != DialogResult.OK)
            return false;
        
        mapPackFileName = saveDlg.FileName;
        mapPackDirectories.Nodes[0].Text = Path.GetFileNameWithoutExtension(mapPackFileName);
        isMapPackNew    = false;
        return WriteMapPack();
    }

    private bool WriteMapPack()
    {
        try
        {
            mapPack.Write(mapPackFileName);
        }
        catch (ApplicationException e)
        {
            System.Windows.MessageBox.Show(e.Message);
            return false;
        }
        catch (Exception e)
        {
            System.Windows.MessageBox.Show(e.ToString());
            return false;
        }

        isMapPackModified = false;
        isMapPackNew      = false;
        
        return true;
    }
}

}
